package net.wwang.blog.commons.zip;

import net.wwang.blog.util.Utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author WangWei
 * @date 2020/8/14
 */
public class ZipUtils {

	private static final int BUFFER_SIZE = 2 * 1024;

	public static void toZip(String srcDir, OutputStream out, boolean keepDirStructure) {
		try (ZipOutputStream zos = new ZipOutputStream(out)) {
			File sourceFile = new File(srcDir);
			compress(sourceFile, zos, sourceFile.getName(), keepDirStructure);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void toZip(List<File> fileList, OutputStream out) {
		try (ZipOutputStream zos = new ZipOutputStream(out)) {
			for (File file : fileList) {
				writeBuffer(file, zos, file.getName());
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static void compress(File sourceFile, ZipOutputStream zos, String name,
	                             boolean keepDirStructure)
			throws IOException {
		if (sourceFile.isFile()) {
			writeBuffer(sourceFile, zos, name);
		} else {
			File[] files = sourceFile.listFiles();
			if (Utils.isEmpty(files)) {
				if (keepDirStructure) {
					try {
						zos.putNextEntry(new ZipEntry(name + File.separator));
					} finally {
						zos.closeEntry();
					}
				}
			} else {
				for (File file : files) {
					if (keepDirStructure) {
						compress(file, zos, name + File.separator + file.getName(),
								keepDirStructure);
					} else {
						compress(file, zos, file.getName(), keepDirStructure);
					}
				}
			}
		}
	}

	private static void writeBuffer(File sourceFile, ZipOutputStream zos, String name)
			throws IOException {
		byte[] buf = new byte[BUFFER_SIZE];
		zos.putNextEntry(new ZipEntry(name));
		int len;
		try (FileInputStream in = new FileInputStream(sourceFile)) {
			while ((len = in.read(buf)) != -1) {
				zos.write(buf, 0, len);
			}
		} finally {
			zos.closeEntry();
		}
	}
}
